package EcNoLineales;

/**
 * @author nhuallpa
 *
 */
public class MetodosIterativos {

	
	public static int k_punto_fijo 	= 1;
	public static int k_newton_rapson = 2;
	public static int k_nr_modificado = 3;
	
	/**
	 * Resuelve ec no lineales con los sig metodos:
	 * 			Punto Fijo
	 * 			Newton_Rapson
	 * 			Newton_Rapson_modificado
	 * 
	 * @param unaFuncion
	 * @param semilla
	 * @param nIteraciones
	 * @param tolerancia
	 * @param metodo
	 */
	public static void puntosFijos(FuncionUnaVariable unaFuncion,
			  			double semilla,
			  			int nIteraciones,
			  			double tolerancia,
			  			int metodo){
		
		double xk = semilla;
		double xk_1=0;
		double tol = 0;
		int n = nIteraciones;
		int it=0;
		System.out.println("it: " + it + " Xk: " + xk );
		do{
			if (metodo == k_punto_fijo)	xk_1=puntoFijo(unaFuncion,xk);
			if (metodo == k_newton_rapson)	xk_1= newtonRapson(unaFuncion,xk);
			if (metodo == k_nr_modificado)	xk_1= nRModificado(unaFuncion,xk);
			tol = Math.abs(xk_1 - xk);
			xk = xk_1;
			it++;
			System.out.println("it: " + it + " Xk: " + xk_1 + " F(xk):"+unaFuncion.valor(xk_1) +" ErrTrn : " + tol);
		}while ((it<=n)&&(tol>tolerancia));
		
	}
	
	/** 
	 * Convergue linealmente
	 * @param unaFuncion
	 * @param xk
	 */
	public static double puntoFijo(FuncionUnaVariable unaFuncion, double xk){
			return (xk - unaFuncion.valor(xk));		
	}
	
	/**
	 * Al iterar, busca la raiz de una ecuacion no lineal con orden 2
	 * Converge cuadraticamente
	 * 
	 * @param unaFuncion
	 * @param semilla
	 */
	public static double newtonRapson(FuncionUnaVariable unaFuncion,double xk){
			double xk_1 = xk - (unaFuncion.valor(xk)/unaFuncion.primerDerv(xk));
			return xk_1;
	}
	
	/**
	 * Al iterar, busca la raiz de una ecuacion no lineal con orden 2
	 * Converge cuadraticamente
	 * 
	 * @param unaFuncion
	 * @param semilla
	 */
	public static double nRModificado(FuncionUnaVariable unaFuncion,double xk){
			double U=(unaFuncion.valor(xk)/unaFuncion.primerDerv(xk));
			double Ui= (( Math.pow(unaFuncion.primerDerv(xk),2)) -(unaFuncion.valor(xk)*unaFuncion.segundaDerv(xk)))/
						(Math.pow(unaFuncion.primerDerv(xk),2));
			double xk_1 = xk -(U/Ui);
			return xk_1;
	}
	
	/**
	 * Para ecuaciones no lineales, donde es dificil obtener la expresion
	 * de la derivada
	 * 
	 * @param unaFuncion
	 * @param unaSemilla
	 * @param otraSemilla
	 * @param nIteraciones
	 * @param tolerancia
	 * @return
	 */
	public static void aplicarSecante(FuncionUnaVariable unaFuncion,
  						double unaSemilla,
  						double otraSemilla,
  						int nIteraciones,
  						double tolerancia){
		
		
		double xk = unaSemilla;
		double xkmas1 = otraSemilla;
		double xk_2=0;
		double tol = 0;
		int n = nIteraciones;
		int it=1;
		System.out.println("it: " + it + " Xk-1: " + xk + " Xk: "+xkmas1);
		do{
			xk_2 = secante(unaFuncion,xk,xkmas1);
			tol = Math.abs(xk_2 - xkmas1);
			xk = xkmas1;
			xkmas1 = xk_2;
			it++;
			System.out.println("it: " + it + " Xk: " + xk_2 + " F(xk):"+unaFuncion.valor(xk_2) +" ErrTrn: " + tol);
		}while ((it<=n)&&(tol>tolerancia));
		

	}
	/**
	 * Al iterar, converge de forma super lineal
	 * 1<O(secante)<2
	 * @param unafuncion
	 * @param unPunto
	 * @param otroPuntoMas1
	 * @return otroPuntoMas2
	 */
	public static double secante(FuncionUnaVariable unafuncion,
								 double unPunto,
								 double otroPuntoMas1){
		double resultado=otroPuntoMas1-
						(otroPuntoMas1-unPunto)*unafuncion.valor(otroPuntoMas1)
						/unafuncion.valor(otroPuntoMas1-unPunto);
		return resultado;
	}
	
}
